#!/var/bin/bash
# -*- coding: utf-8 -*-
import os
import time

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
from matplotlib.patches import ConnectionPatch
import numpy as np
import pandas as pd

zhfont = matplotlib.font_manager.FontProperties(fname='/usr/share/fonts/truetype/arphic/ukai.ttc')


def float_time_to_str_time(x, pos):
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(x))


class MatplotlibDrawManager(object):

    def __init__(self):
        self.fig = None
        self.axes = None

    def creat_figure(self, *args, **kwargs):
        """
            num : int or str or `.Figure`, optional
                图形的唯一标识符。如果未给出num，则创建一个新图形，使其处于活动状态并返回。
            figsize : (float, float), default: :rc:`figure.figsize`default: [6.4, 4.8]
                (宽, 高)英寸
            dpi : float, default: :rc:`figure.dpi`(default: 100.0)
                以每英寸点数为单位的图形分辨率。
            facecolor : color, default: :rc:`figure.facecolor`(default: 'white')
                背景颜色。
            edgecolor : color, default: :rc:`figure.edgecolor`(default: 'white')
                边框颜色。
            frameon : bool, default: True
                如果为False，则禁止绘制图框。
            FigureClass : subclass of `~matplotlib.figure.Figure`
                可选择使用自定义Figure实例。
            clear : bool, default: False
                如果为True并且该图形已经存在，则将其清除
            tight_layout : bool or dict, default: :rc:`figure.autolayout` (default: False)
                紧密布局。如果为False，则使用subplotpars。
                如果为True，则使用带默认填充的tight_layout调整subplot参数。
                当提供包含keys pad, w_pad, h_pad, and rect，默认的紧密布局填充将被覆盖。
            constrained_layout : bool, default: :rc:`figure.constrained_layout.use` (default: False)
                约束布局。
        """
        self.fig = plt.figure(*args, **kwargs)  # an empty figure with no Axes

    @staticmethod
    def close_figure():
        plt.close()

    def plot_draw(self, x=None, y=None, label=None):
        """
        折线图绘制
        :param x:X轴数据
        :param y:Y轴数据
        :param label: Y轴标签
        :return:
        """
        """
        plot(*args, scalex=True, scaley=True, data=None, **kwargs)
        Parameters:
            x, y: array-like or scalar
                数据点的水平/垂直坐标。 x值是可选的，默认为range(len(y))。通常，这些参数是一维数组。它们也可以是标量或二维的（在这种情况下，列表示单独的数据集）。这些参数不能作为关键字传递。

            fmt：str, optional
                格式字符串，例如红色圆圈的“ro”。有关格式字符串的完整说明，请参阅注释 部分。格式字符串只是快速设置基本行属性的缩写。所有这些以及更多也可以通过关键字参数来控制。
                此参数不能作为关键字传递。
            data：indexable object, optional
                带有标签数据的对象。如果给定，请提供要在x和y中绘制的标签名称。

        Other Parameters：
            scalex, scaley：bool, default: True
                这些参数确定视图限制是否适应数据限制。值被传递给autoscale_view.

            **kwargsLine2D properties, optional：
                kwargs用于指定线标签（用于自动图例）、线宽、抗锯齿、标记面颜色等属性。例子：
                    plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2)
                    plot([1, 2, 3], [1, 4, 9], 'rs', label='line 2')
                如果您在一次绘图调用中指定多行，则 kwargs 适用于所有这些行。如果标签对象是可迭代的，则每个元素都用作每组数据的标签。
                以下是可用Line2D属性的列表：

                Property                            Description
                ------------------------------------------------------------------------------------------------------------
                agg_filter                          一个过滤函数，它接受一个 (m, n, 3) 浮点数组和一个 dpi 值，并返回一个 (m, n, 3) 数组
                alpha                               标量或无
                animated                            bool
                antialiased or aa                   bool
                clip_box                            Bbox
                clip_on                             bool
                clip_path                           Patch or (Path, Transform) or None
                color or c                          color
                dash_capstyle                       CapStyle或 {'butt', 'projecting', 'round'}
                dash_joinstyle                      JoinStyle或 {'miter', 'round', 'bevel'}
                dashes                              浮动序列（以点为单位的开/关墨水）或（无，无）
                data                                (2, N) 数组或两个一维数组
                drawstyle or ds                     {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'}，默认值：'default'
                figure                              Figure
                fillstyle                           {'full', 'left', 'right', 'bottom', 'top', 'none'}
                gid                                 str
                in_layout                           bool
                label                               object
                linestyle or ls                     {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
                linewidth or lw                     float
                marker                              标记样式字符串，Path或MarkerStyle
                markeredgecolor or mec              color
                markeredgewidth or mew              float
                markerfacecolor or mfc              color
                markerfacecoloralt or mfcalt        color
                markersize or ms                    float
                markevery                           无或 int 或 (int, int) 或 slice 或 list[int] 或 float 或 (float, float) 或 list[bool]
                path_effects                        AbstractPathEffect
                picker                              浮动或可调用[[Artist, Event], tuple[bool, dict]]
                pickradius                          float
                rasterized                          bool
                sketch_params                       (scale: float, length: float, randomness: float)
                snap                                bool or None
                solid_capstyle                      CapStyle or {'butt', 'projecting', 'round'}
                solid_joinstyle                     JoinStyle or {'miter', 'round', 'bevel'}
                transform                           unknown
                url                                 str
                visible                             bool
                xdata                               1D array
                ydata                               1D array
                zorder                              float
        """
        # 添加一个图
        ax = self.fig.add_subplot(1, 1, 1)
        ax.plot(x, y, "--", label=label)
        plt.xticks(rotation=30)
        ax.xaxis.set_major_formatter(float_time_to_str_time)
        file_name = "plot.png"
        plt.savefig(file_name, format="png")
        plt.clf()

    def histogram_generation(self, value_list, mean, std):
        """
        直方图生成
        :param std:
        :param mean:
        :param value_list:
        :return:
        """
        """
        Plt.hist(x,bins=10,range=None,normed=False,weights=None,cumulative=False,bottom=None,histtype=’bar’,
                align=’mid’,orientation=’vertical’,rwidth=None,log=False,color=None,edgecolor=None,label=None,stacked=False)
            1）、x:指定要绘制直方图的数据。
            2）、bins：指定直方图条形的个数。
            3）、range：指定直方图数据的上下界，默认包含绘图数据的最大值和最小值。
            4）、normed：是否将直方图的频数转换成频率。
            5）、weights：该参数可为每一个数据节点设置权重。
            6）、cumulative：是否需要计算累积频数或频率。
            7）、bottom：可以为直方图的每个条形添加基准线，默认为0.
            8）、histtype：指定直方图的类型，默认bar，其他八日stacked、step和stepfilled。
            9）、align：设置条形边界的对齐方式，默认mid,另外left和right。
            10）、orientation：设置直方图的摆放方向，默认vertical垂直方向。
            11）、rwidth：设置直方图条形的宽度。
            12）、log：是否需要对绘图数据进行log变换。
            13）、color：设置直方图的填充色。
            14）、edgecolor：设置直方图边框色。
            15）、label：设置直方图的标签，可通过legend展示图例。
            16）、stacked：当有多个数据时，是否需要将直方图呈堆叠摆放，默认水平摆放。
        """

        fig, ax = plt.subplots()
        n, bins, patches = ax.hist(value_list, 30, density=False, edgecolor="#000000")
        # y = norm.pdf( bins, mean, std) * (np.max(n) - np.min(n))
        cc = 90
        dd = 90
        line_max = ax.viewLim.ymax
        lower_min = 0
        upper_min = 0
        for i, number in enumerate(bins):
            if abs(number - 3.6) < cc:
                cc = abs(number - 3.6)
                lower_min = n[i] / line_max
            if abs(number - 4.4) < dd:
                dd = abs(number - 4.4)
                upper_min = n[i] / line_max
                # print(upper_min)

        y = ((1 / (np.sqrt(2 * np.pi) * std)) * np.exp(-0.5 * (1 / std * (bins - mean)) ** 2)) * line_max
        ax.plot(bins, y, '-')
        ax.axvline(3.6, ymin=lower_min, c="g", ls='--', label='3.6')
        ax.axvline(4.4, ymin=upper_min, c="r", ls='--', label='4.4')
        textstr = '\n'.join((
            r'均值=%.2f' % mean,
            r'标准差=%.2f' % std,
            r'N = %d' % len(value_list)))
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
        ax.text(1.05, 0.95, textstr, transform=ax.transAxes, fontsize=12,
                verticalalignment='top', bbox=props, fontproperties=zhfont)
        ax.set_xlabel('异形比', fontproperties=zhfont)
        ax.set_ylabel('频率', fontproperties=zhfont)
        ax.set_title('异形比的直方图\n', fontproperties=zhfont)

        fig.tight_layout()
        ax.legend()
        # plt.show()
        file_name = "histogram.png"
        plt.savefig(file_name, format="svg")
        return os.path.abspath(file_name)

    @staticmethod
    def random_normal_distribution(x, mu, sigma):
        """
        生成符合要求的正态分布数组
        :param x:
        :param mu:
        :param sigma:
        :return:
        """
        # 根据均值、标准差,求指定范围的正态分布概率值
        # 关于seed()函数用法：
        # seed( ) 用于指定随机数生成时所用算法开始的整数值。
        # 1.如果使用相同的seed( )值，则每次生成的随即数都相同；
        # 2.如果不设置这个值，则系统根据时间来自己选择这个值，此时每次生成的随机数因时间差异而不同。
        # np.random.seed(19680801)
        # mean = 100  # 平均值
        # std = 15  # 标准差
        # x = mean + std * np.random.randn(437)
        # num_bins = 50

        y = np.exp(-((x - mu) ** 2) / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi))
        return y

    def pie_generation(self, x, labels):
        """
        饼图生成
        :return:
        """
        """
        pie(x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=0, radius=1, 
        counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False, rotatelabels=False, *, normalize=True, data=None)
        Parameters
            x:1维数组
                楔体数据
            explode：array-like, default: None
                如果没有，则是一个len（x）数组，用于指定偏移每个楔体的半径分数。
            labels：list, default: None
                为每个楔块提供标签的一系列字符串
            colors：array-like, default: None
                饼图将循环的一系列颜色。如果没有，将使用当前活动周期中的颜色。
            autopct：None or str or callable, default: None
                如果为空，一个字符串或函数，用于用其标记楔体数值。标签将放置在楔子内。如果是格式字符串，则标签将为fmt%pct。如果是函数，则将调用它。      
            pctdistance：float, default: 0.6
                每个饼图切片的中心与AutoCT生成的文本开始之间的比率。如果AutoCT为无，则忽略。
            shadow:bool, default: False
                在馅饼下面画一个阴影。
            normalize:bool, default: True
                如果为True，则始终通过规范化x来生成完整饼图，使总和（x）==1。如果总和（x）<=1，则为False生成部分饼图，并为总和（x）大于1引发ValueError。
            labeldistance:float or None, default: 1.1
                绘制饼图标签的径向距离。如果设置为“无”，则不会绘制标签，而是将其存储以供在legend()中使用
            startangle:float, default: 0 degrees
                饼图起点相对于x轴逆时针旋转的角度。
            radius:float, default: 1
                饼图的半径。  
            counterclock:bool, default: True
                指定分数方向，顺时针或逆时针。
            wedgeprops：dict, default: None
                传递给制作饼图的楔形对象的参数的Dict。例如，可以传入wedgeprops={linewidth:3}，将楔形边框线的宽度设置为3。
                有关更多详细信息，请查看wedge对象的doc/arguments。默认情况下，clip_on=False。
            textprops：dict, default: None
                传递给文本对象的参数的Dict。
            center：(float, float), default: (0, 0)
                图表中心的坐标。
            frame：bool, default: False
                如果为true，则用图表绘制轴框架。
            rotatelabels:bool, default: False
                如果为true，则将每个标签旋转到相应切片的角度。
            data:indexable object, optional
                如果给定，以下参数也接受字符串s，该字符串被解释为data[s]（除非这引发异常）：x, explode, labels, colors
            """
        labels = ('1', '2')
        x = [50, 50]
        explode = (0, 0.3)

        x1 = [10, 20, 20]
        labels1 = ('Hogs', 'Dogs', 'Logs')
        # explode1 = (0, 0, 0)
        ax1 = self.fig.add_subplot(1, 2, 1)
        ax2 = self.fig.add_subplot(1, 2, 2)
        radius = 1.5
        startangle = x[1] * 1.8
        wedges, *_ = ax1.pie(x, explode=explode, labels=labels, autopct='%1.1f%%', pctdistance=0.5, labeldistance=1.1,
                             normalize=True,
                             shadow=True, startangle=startangle, counterclock=True, frame=False, rotatelabels=False)
        ax2.pie(x1, labels=labels1, autopct=lambda p: '{:,.1f}%'.format(p * sum(x1) / 100),
                pctdistance=0.5, labeldistance=1.1, radius=radius,
                normalize=True,
                shadow=True, startangle=0, counterclock=True, frame=False, rotatelabels=True)

        width = 0.5

        theta1, theta2 = wedges[0].theta1, wedges[0].theta2
        center, r = wedges[0].center, wedges[0].r

        # draw top connecting line
        x = r * np.cos(np.pi / 180 * theta1) + center[0]
        y = r * np.sin(np.pi / 180 * theta1) + center[1]
        con = ConnectionPatch(xyA=(-width / 2, radius), coordsA=ax2.transData,
                              xyB=(x, y), coordsB=ax1.transData)
        con.set_color([0, 0, 0.1])
        con.set_linewidth(0.4)
        con.set_linestyle("--")
        ax2.add_artist(con)
        #
        # # draw bottom connecting line
        x = r * np.cos(np.pi / 180 * theta2) + center[0]
        y = r * np.sin(np.pi / 180 * theta2) + center[1]
        con = ConnectionPatch(xyA=(-width / 2, -radius), coordsA=ax2.transData,
                              xyB=(x, y), coordsB=ax1.transData)

        con.set_color([0, 0, 0.1])
        con.set_linestyle("--")
        con.set_linewidth(0.4)
        ax2.add_artist(con)
        # ax.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
        file_name = "pie.png"
        plt.savefig(file_name, format="jpg")
        return os.path.abspath(file_name)
        # plt.show()

    @staticmethod
    def bar_generation(label_value, labels):
        """
        生成一个柱状图。
        :param label_value:
        :param labels:
        :return:
        """
        """
        这些条按给定的对齐方式定位在x处。 它们的尺寸由高和宽给出。 垂直基线是底部(默认0)。
        许多参数可以是应用于所有条的单个值，也可以是应用于每个条的一系列值。
        bar(x, height, width=0.8, bottom=None, *, align='center', data=None, **kwargs)
        Parameters：
            x: float or array-like  x坐标轴条。 请参见“对齐”以了解条形图与坐标的对齐方式。
            height： float or array-like  条轴的高度
            width：float or array-like  条轴的宽度，默认为0.8
            bottom：float or array-like, y坐标的基准，默认为0
            align：{'center', 'edge'}, 将条形图与x坐标对齐:
                        'center':将基础置于x位置的中心。
                        'edge':将条的左侧边缘与x位置对齐。
                        要对齐右边的条，请输入负的宽度，并输入align='edge'。
        Other Parameters：
            color：color or list of color, optional 条轴颜色
            edgecolor:color or list of color, optional 条轴边框颜色
            linewidth：float or array-like, optional 条轴边框宽度 为0，不花边框
            tick_label：str or list of str, optional 条形图的标签。 默认值:无(使用默认数值标签)
            xerr, yerr:float or array-like of shape(N,) or shape(2, N), optional
            ecolor：color or list of color, default: 'black'   错误条的线颜色。
            capsize：float, default: rcParams["errorbar.capsize"] (default: 0.0)   误差杆的长度以点为单位。
            capsize：float, default: rcParams["errorbar.capsize"] (default: 0.0)   误差杆的长度以点为单位。
        """
        x = np.arange(len(labels))
        fig, ax = plt.subplots()
        rects1 = ax.bar(x, label_value, 0.3, color='#ff0000')
        ax.set_xticks(x, labels, fontproperties=zhfont)
        ax.set_title('缺陷平均处理时长\n', fontproperties=zhfont, fontsize=20)
        ax.set_ylabel('时长（分钟）', fontproperties=zhfont)
        ax.bar_label(rects1, padding=2)
        fig.tight_layout()
        plt.show()
        plt.close()
